package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CustomException;
import com.heima.model.common.constants.WemediaConstants;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmNewsTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
  @Autowired private WmNewsMaterialMapper wmNewsMaterialMapper;
  @Autowired private WmMaterialMapper wmMaterialMapper;
  @Autowired private WmNewsMapper wmNewsMapper;
  @Autowired private WmNewsTaskService wmNewsTaskService;
  @Autowired private KafkaTemplate<String, String> kafkaTemplate;

  /**
   * 查询文章
   *
   * @param dto
   * @return
   */
  @Override
  public ResponseResult findAll(WmNewsPageReqDto dto) {

    // 1.检查参数
    if (dto == null) {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }
    // 分页参数检查
    dto.checkParam();
    // 获取当前登录人的信息
    WmUser user = WmThreadLocalUtil.getUser();
    if (user == null) {
      return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
    }

    // 2.分页条件查询
    IPage page = new Page(dto.getPage(), dto.getSize());
    LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    // 状态精确查询
    if (dto.getStatus() != null) {
      lambdaQueryWrapper.eq(WmNews::getStatus, dto.getStatus());
    }

    // 频道精确查询
    if (dto.getChannelId() != null) {
      lambdaQueryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
    }

    // 时间范围查询
    if (dto.getBeginPubdate() != null && dto.getEndPubdate() != null) {
      lambdaQueryWrapper.between(
          WmNews::getPublishTime, dto.getBeginPubdate(), dto.getEndPubdate());
    }

    // 关键字模糊查询
    if (StringUtils.isNotBlank(dto.getKeyword())) {
      lambdaQueryWrapper.like(WmNews::getTitle, dto.getKeyword());
    }

    // 查询当前登录用户的文章
    lambdaQueryWrapper.eq(WmNews::getUserId, user.getId());

    // 发布时间倒序查询
    lambdaQueryWrapper.orderByDesc(WmNews::getCreatedTime);

    page = page(page, lambdaQueryWrapper);

    // 3.结果返回
    ResponseResult responseResult =
        new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
    responseResult.setData(page.getRecords());

    return responseResult;
  }

  /**
   * 发布修改文章或保存为草稿
   *
   * @param dto
   * @return
   */
  @Override
  public ResponseResult submitNews(WmNewsDto dto) {

    // 0.条件判断
    if (dto == null || dto.getContent() == null) {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }

    // 1.保存或修改文章
    WmNews wmNews = new WmNews();
    // 属性拷贝 属性名词和类型相同才能拷贝
    BeanUtils.copyProperties(dto, wmNews);
    // 封面图片  list---> string
    if (dto.getImages() != null && dto.getImages().size() > 0) {
      // [1dddfsd.jpg,sdlfjldk.jpg]-->   1dddfsd.jpg,sdlfjldk.jpg
      // 底层用StringBuilder实现
      String imageStr = StringUtils.join(dto.getImages(), ",");
      wmNews.setImages(imageStr);
    }
    // 如果当前封面类型为自动 -1
    if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
      wmNews.setType(null);
    }
    saveOrUpdateWmNews(wmNews);

    // 2.判断是否为草稿  如果为草稿结束当前方法
    if (dto.getStatus().equals(WmNews.Status.NORMAL.getCode())) {
      return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    // 3.不是草稿，保存文章内容图片与素材的关系
    // 获取到文章内容中的图片信息
    List<String> materials = ectractUrlInfo(dto.getContent());
    saveRelativeInfoForContent(materials, wmNews.getId());

    // 4.不是草稿，保存文章封面图片与素材的关系，如果当前布局是自动，需要匹配封面图片
    saveRelativeInfoForCover(dto, wmNews, materials);

    // 新增发布任务
    wmNewsTaskService.addNewsToTask(wmNews.getId(), wmNews.getPublishTime());
    return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);

    // 文章图片审核(发布任务，而不是立即调用异步审核)
    /*wmNewsAutomaticReviewService.newsAutomaticReview(wmNews.getId());
    return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);*/
  }

  /**
   * 根据文章id查询文章详情
   *
   * @param id
   * @return
   */
  @Override
  public ResponseResult findOne(Integer id) {
    // 参数校验
    if (ObjectUtils.isEmpty(id)) {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }
    WmNews wmNews = wmNewsMapper.selectById(id);
    if (ObjectUtils.isEmpty(wmNews)) {
      return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
    }
    return ResponseResult.okResult(wmNews);
  }

  /**
   * 删除文章
   *
   * @param id
   * @return
   */
  @Override
  public ResponseResult delNews(Integer id) {
    // 参数校验
    if (ObjectUtils.isEmpty(id)) {
      return ResponseResult.errorResult(501, "文章id不可缺少");
    }
    // 根据id查询文章详情
    WmNews wmNews = wmNewsMapper.selectById(id);
    if (ObjectUtils.isEmpty(wmNews)) {
      return ResponseResult.errorResult(1002, "文章不存在");
    }

    if (wmNews.getStatus() == 9) {
      return ResponseResult.errorResult(501, "文章已发布，不能删除");
    }
    try {
      // 删除文章信息
      wmNewsMapper.deleteById(id);
      // 根据文章id查询素材关联表
      LambdaQueryWrapper<WmNewsMaterial> qw = new LambdaQueryWrapper<>();
      qw.eq(WmNewsMaterial::getNewsId, id);
      wmNewsMaterialMapper.delete(qw);
      log.info("删除文章成功");
    } catch (Exception e) {
      e.printStackTrace();
      log.error("删除失败");
    }
    return ResponseResult.okResult(200, "操作成功");
  }

  /**
   * 文章上下架
   *
   * @param dto
   * @return
   */
  @Override
  public ResponseResult downOrUp(WmNewsDto dto) {
    // 参数校验
    if (ObjectUtils.isEmpty(dto)) {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }
    // 根据文章id查询
    WmNews wmNews = wmNewsMapper.selectById(dto.getId());
    if (ObjectUtils.isEmpty(wmNews)) {
      return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
    }
    wmNews.setEnable(dto.getEnable().shortValue());
    try {
      wmNewsMapper.updateById(wmNews);
      log.info("文章id：{}，下架成功", wmNews.getArticleId());
    } catch (Exception e) {
      e.printStackTrace();
      log.error("文章id：{}，下架失败", wmNews.getArticleId());
    }
    // 发送异步消息
    HashMap<String, String> map = new HashMap<>();
    map.put("article_id", wmNews.getArticleId().toString());
    map.put("enable", dto.getEnable().toString());
    String jsonStr = JSON.toJSONString(map);
    kafkaTemplate.send("down_or_up", jsonStr);
    return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
  }

  /**
   * 第一个功能：如果当前封面类型为自动，则设置封面类型的数据 匹配规则： 1，如果内容图片大于等于1，小于3 单图 type 1 2，如果内容图片大于等于3 多图 type 3
   * 3，如果内容没有图片，无图 type 0
   *
   * <p>第二个功能：保存封面图片与素材的关系
   *
   * @param dto
   * @param wmNews
   * @param materials
   */
  private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {

    List<String> images = dto.getImages();

    // 如果当前封面类型为自动，则设置封面类型的数据
    if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
      // 多图
      if (materials.size() >= 3) {
        wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
        images = materials.stream().limit(3).collect(Collectors.toList());
      } else if (materials.size() >= 1 && materials.size() < 3) {
        // 单图
        wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
        images = materials.stream().limit(1).collect(Collectors.toList());
      } else {
        // 无图
        wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
      }

      // 修改文章
      if (images != null && images.size() > 0) {
        wmNews.setImages(StringUtils.join(images, ","));
      }
      updateById(wmNews);
    }
    if (images != null && images.size() > 0) {
      saveRelativeInfo(images, wmNews.getId(), WemediaConstants.WM_COVER_REFERENCE);
    }
  }

  /**
   * 处理文章内容图片与素材的关系
   *
   * @param materials
   * @param newsId
   */
  private void saveRelativeInfoForContent(List<String> materials, Integer newsId) {
    saveRelativeInfo(materials, newsId, WemediaConstants.WM_CONTENT_REFERENCE);
  }

  /**
   * 保存文章图片与素材的关系到数据库中
   *
   * @param materials
   * @param newsId
   * @param type
   */
  private void saveRelativeInfo(List<String> materials, Integer newsId, Short type) {
    if (materials != null && !materials.isEmpty()) {
      // 通过图片的url查询素材的id
      List<WmMaterial> dbMaterials =
          wmMaterialMapper.selectList(
              Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, materials));

      // 判断素材是否有效
      if (dbMaterials == null || dbMaterials.size() == 0) {
        // 手动抛出异常   第一个功能：能够提示调用者素材失效了，第二个功能，进行数据的回滚
        throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
      }

      if (materials.size() != dbMaterials.size()) {
        throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
      }

      List<Integer> idList =
          dbMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());

      // 批量保存
      wmNewsMaterialMapper.saveRelations(idList, newsId, type);
    }
  }

  /**
   * 提取文章内容中的图片信息
   *
   * @param content
   * @return
   */
  private List<String> ectractUrlInfo(String content) {
    List<String> materials = new ArrayList<>();

    List<Map> maps = JSON.parseArray(content, Map.class);
    for (Map map : maps) {
      if (map.get("type").equals("image")) {
        String imgUrl = (String) map.get("value");
        materials.add(imgUrl);
      }
    }

    return materials;
  }

  /**
   * 保存或修改文章
   *
   * @param wmNews
   */
  private void saveOrUpdateWmNews(WmNews wmNews) {
    // 补全属性
    wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
    wmNews.setCreatedTime(new Date());
    wmNews.setSubmitedTime(new Date());
    wmNews.setEnable((short) 1); // 默认上架

    if (wmNews.getId() == null) {
      // 保存
      save(wmNews);
    } else {
      // 修改
      // 删除文章图片与素材的关系
      wmNewsMaterialMapper.delete(
          Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNews.getId()));
      updateById(wmNews);
    }
  }
}
